%{

using namespace std;

#include <cstring>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <utility>

#include "commun.h"
#include "XML_Document.h"
#include "XML_Element.h"
#include "XML_Noeud.h"
#include "XML_Texte.h"
#include "XML_Attribut.h"
#include "xml.tab.h"


static XML_Document * xml_tree;

void xmlerror( char * msg );
int xmllex( void );

%}

%union
{
   char * s;
   ElementName * en;  /* le nom d'un element avec son namespace */
   XML_Document * doc;
   XML_Element * el;
   vector<XML_Attribut *> * list_attr;
   XML_Attribut * attr;
   vector<XML_Noeud *> * sub_knots;
   
}

%token EQ SLASH CLOSE END CLOSESPECIAL DOCTYPE
%token <s> ENCODING VALUE DATA COMMENT NAME NSNAME
%token <en> NSSTART START STARTSPECIAL

%type <doc> document
%type <el> element
%type <en> start declarations declaration
%type <list_attr> attributes
%type <attr> attribute
%type <sub_knots> empty_or_content content close_content_and_end

%%

document :
	declarations element misc_seq_opt
	{
		xml_tree = new XML_Document();
		xml_tree->setRoot( $2 );
		xml_tree->setDTD( $1->first, $1->second );
	}
;

declarations :
	declaration
	{
		$$ = $1;
	}
|	/* empty */
	{
		$$ = new ElementName;
		$$->first = "";
		$$->second = "";
	}
;

declaration :
	DOCTYPE NAME NAME VALUE CLOSE
	{
		$$ = new ElementName;
		$$->first = $2;
		$$->second = $4;
	}
;

element :
	start attributes empty_or_content
	{
		$$ = new XML_Element( $1->second );
		$$->setAttributes( $2 );
		$$->setSubKnots( $3 );
	}
;

start :
	START
	{
		$$ = $1;
	}
|	NSSTART
	{
		$$ = $1;
	}
;

attributes :
	attributes attribute
	{
		$$ = $1;
		$$->push_back( $2 );
	}
|	/* empty */
	{
		$$ = new vector<XML_Attribut *>();
	}
;

attribute :
	NAME EQ VALUE
	{
		$$ = new XML_Attribut( $1, $3 );
	}
;

empty_or_content :
	SLASH CLOSE
	{
		$$ = NULL;
	}
|	close_content_and_end name_or_nsname_opt CLOSE
	{
		$$ = $1;
	}
;

close_content_and_end :
	CLOSE content END
	{
		$$ = $2;
	}
;

content :
	content DATA
	{
		$$ = $1;
		$$->push_back( new XML_Texte( $2 ) );
	}
|	content misc
	{
		$$ = $1; /* on ignore les commentaires */
	}
|	content element
	{
		$$ = $1;
		$$->push_back( $2 );
	}
|	/* empty */
	{
		$$ = new vector<XML_Noeud *>();
	}
;

misc_seq_opt :
	misc_seq_opt misc
|	/* empty */
;
 
misc :
	COMMENT		
;

name_or_nsname_opt :
	NAME
|	NSNAME
|	/* empty */
;

%%

XML_Document * getXMLTree()
{
	return xml_tree;
}

void xmlerror( char * msg )
{
	fprintf( stderr, "%s\n", msg );
}